import { Component, ViewChild, Input, Output, EventEmitter } from '@angular/core';
import { PortfolioService } from '../portfolio.service';
import { LrtmService, LongRunningTaskTypeEnum, LongRunningTaskInstanceStatusEnum } from '../../../framework/lrtm/lrtm.service';
import { StorageService } from '../../../shared/services/storage.service';
import { AppComponent } from '../../../app.component';
import { Subscription } from 'rxjs/Subscription';
import { PortfolioFilterModel } from '../models/portfolioFilter.model';
import { ColumnOptions } from '../../../shared/components/table/models/columnOptions.model';
import { PaginationPositionDisplayEnum, TableComponent } from '../../../shared/components/table/table.component';
import { TableRouterLink } from '../../../shared/components/table/models/tableRouterLink.model';
import { TableOptions } from '../../../shared/components/table/models/tableOptions.model';
import { TableButton } from '../../../shared/components/table/models/tableButton.model';
import { PortfolioAction } from '../models/portfolioAction.model';
import { SearchType } from '../../../shared/components/search/search.service';
import { CompanySearchComponent } from '../../../shared/components/search/company-search/company-search.component';
import { PortfolioType } from '../models/portfolioType.model';
import { NgxSmartModalService } from 'ngx-smart-modal';
import swal, { SweetAlertOptions } from 'sweetalert2';
import { UtilsService } from '../../../shared/services/utils.service';
import { GoogleAnalyticsBeacon } from '../../../shared/models/googleAnalytics.model';
import { AnalyticsService } from '../../../shared/services/googleAnalytics.service';

@Component({
    selector: 'portfolio-creation',
    templateUrl: './portfolioCreation.component.html',
    styleUrls: ['./portfolioCreation.component.scss', '../../../../assets/table.scss'],
    providers: [PortfolioService]
})
export class PortfolioCreationComponent {
    constructor(
        private rootComponent: AppComponent,
        private portfolioService: PortfolioService,
        private lrtmService: LrtmService,
        public ngxSmartModalService: NgxSmartModalService,
        private analyticsService: AnalyticsService
    ) { }

    @ViewChild('securityNotMatchedTable') securityNotMatchedTable: TableComponent;
    @ViewChild('securityMatchedTable') securityMatchedTable: TableComponent;
    @ViewChild('portfolioSearchComponent') portfolioSearchComponent: CompanySearchComponent;
    @ViewChild('fileInput') fileInput: any;

    @Output() reloadPortfolios: EventEmitter<any> = new EventEmitter();

    public files: any[] = [];
    public securityNotMatchedSource: any[] = [];
    public securityMatchedSource: any[] = [];
    public securityNotMatchedColumns: ColumnOptions[] = [];
    public securityNotMatchedCount: number = 0;
    public securityMatchedColumns: ColumnOptions[] = [];
    public securityMatchedCount: number = 0;
    public searchTypePortfolio: SearchType = SearchType.portfolio;
    public searchTypeCompany: SearchType = SearchType.company;
    public paginationPosition = PaginationPositionDisplayEnum.Down;
    public portfolioNameSearch: string = "";
    public sharingStatus: boolean;

    public nrOfCompaniesNotMatched: number = 0;

    public currentSkipValid: number = 0;
    public currentTakeValid: number = 5;
    public currentSkipInvalid: number = 0;
    public currentTakeInvalid: number = 5;

    public idNewPortfolio: string;

    public showFirstStep: boolean = true;
    public showSecondStep: boolean = false;
    public saveDisabled = false;

    public resetForm() {
        this.showFirstStep = true;
        this.showSecondStep = false;
        this.saveDisabled = false;

        this.securityNotMatchedColumns = [];
        this.securityMatchedColumns = [];

        this.securityMatchedSource = [];
        this.securityNotMatchedSource = [];

        this.securityMatchedCount = 0;
        this.securityNotMatchedCount = 0;

        this.portfolioSearchComponent.clearAndFocusInput();
        this.portfolioNameSearch = "";
        this.idNewPortfolio = "";
        this.files = [];

    }

    private setSecurityNotMatchedColumns() {
        this.securityNotMatchedColumns = [
            new ColumnOptions('SecurityName', 'SecurityName', 'Security Name', 'col-md-2', false, false, false, undefined, false, false, false, true, undefined, false, false, true),
            new ColumnOptions('SecurityID', 'SecurityID', 'Security ID', 'col-md-1', false, false, false, undefined, false, false, false, true, undefined, false, false, true),
            new ColumnOptions('SecurityWeight', 'SecurityWeight', 'Security Weight', 'col-md-1', false, false, false, undefined, false, false, false, true, undefined, false, true, false),
            new ColumnOptions('PotentialMatches', 'PotentialMatches', 'Potential Matches', 'col-md-3', false, false, false, undefined, false, false, false, true, undefined, false, false, true, true),
            new ColumnOptions('MatchedID', 'MatchedID', 'Matched ID', 'col-md-2', false, false, false, undefined, false, false, false, true, undefined, false, false, true, true),
            new ColumnOptions('Action', 'Action', 'Action', 'col-md-3', false, false, false, undefined, false, false, true, true, undefined, false, false, false, true)
        ];
    }

    private setSecurityMatchedColumns() {
        this.securityMatchedColumns = [
            new ColumnOptions('SecurityName', 'SecurityName', 'Security Name', 'col-md-2', false, false, false, undefined, false, false, false, true, undefined, false, false, true),
            new ColumnOptions('SecurityID', 'SecurityID', 'Security ID', 'col-md-2', false, false, false, undefined, false, false, false, true, undefined, false, false, true),
            new ColumnOptions('SecurityWeight', 'SecurityWeight', 'Security Weight', 'col-md-2', false, false, false, undefined, false, false, false, true, undefined, false, true, false),
            new ColumnOptions('MatchedCompanyName', 'MatchedCompanyName', 'Matched Company Name', 'col-md-2', false, false, false, undefined, false, true, false, true),
            new ColumnOptions('MatchedID', 'MatchedID', 'MatchedID', 'col-md-2', false, false, false, undefined, false, false, false, true, undefined, false, false, true),
            new ColumnOptions('Action', 'Action', 'Action', 'col-md-2', false, false, false, undefined, false, false, true, true)
        ];
    }

    public onImportMatchedClicked() {
        let params = {
            portfolioName: this.portfolioNameSearch
        };
        this.lrtmService.runTask(this.rootComponent, "Download portfolio matched securities", LongRunningTaskTypeEnum.PortfolioMatchedSecuritiesDownload, params, true, null).subscribe(idNewTask => {
            let subscriptionUpload = this.lrtmService.tasksStatusUpdated
                .subscribe(task => {
                    if (task.id == idNewTask) {
                        if (task.taskInstanceStatus == LongRunningTaskInstanceStatusEnum.Finished) {
                            this.reloadPortfolios.emit("refresh");
                            this.rootComponent.showSuccess("Portfolio successfully created.", "Success");
                            this.analyticsService.sendBeacon(new GoogleAnalyticsBeacon('AddPortfolio', 'Portfolio Management', { PortfolioName: this.portfolioNameSearch }));
                            subscriptionUpload.unsubscribe();
                            this.resetForm();
                        }
                        else if (task.taskInstanceStatus == LongRunningTaskInstanceStatusEnum.Failed) {
                            this.rootComponent.showError("An error has occured. Portfolio creation failed.");
                            subscriptionUpload.unsubscribe();
                        }
                    }
                });
        }

        );

    }

    public onCancelImportClicked() {
        this.saveDisabled = false;
        this.portfolioService.deleteAllMatches(this.portfolioNameSearch).subscribe(data => {
        });
        this.resetForm();
    }

    public downloadTemplate() {
        this.lrtmService.runTask(this.rootComponent, 'Download securities template',
            LongRunningTaskTypeEnum.PortfolioSecuritiesDownloadTemplate, null, true, null
        ).subscribe(data => {
            // this.ngxSmartModalService.getModal('portfolioCreationModal').close();
        });
    }

    public onFileUploaded(event) {
        if (event.target.files && event.target.files.length > 0) {
            this.files[0] = event.target.files[0];
            if (!this.validExcelFile(this.files[0].name)) {
                this.rootComponent.showError("Please select an xls or xlsx file.");
                this.fileInput.files = null;
                this.files = [];
            }
            if (this.portfolioNameSearch.length > 0) {
                this.saveDisabled = false;
            }
        }
    }

    private validExcelFile(file): boolean {
        let validExts = new Array(".xlsx", ".xls");
        let fileExt = file.substring(file.lastIndexOf('.'));
        if (validExts.indexOf(fileExt) < 0) {
            return false;
        }
        else return true;
    }

    public onSaveClicked() {
        if (this.files.length == 0) {
            this.rootComponent.showError("No file selected! Please choose a file.");
            return;
        }
        this.portfolioNameSearch = this.portfolioSearchComponent.term;
        if (this.portfolioNameSearch.length == 0) {
            this.rootComponent.showError("No name introduced. Please write a name.");
            return;
        }
        if (this.portfolioNameSearch.lastIndexOf('/') > 0) {
            this.rootComponent.showError("The portfolio name must not contain the '/' character.");
            return;
        }
        let filter: PortfolioFilterModel = new PortfolioFilterModel();
        filter.namePortfolio = this.portfolioNameSearch;
        filter.isNameEqual = true;
        this.portfolioService
            .getPortfolioCount(filter, PortfolioType.Custom)
            .subscribe(data => {
                if (data == null) {
                    this.saveDisabled = true;
                    this.save();
                } else {
                    const swalOptions: SweetAlertOptions = Object.assign(UtilsService.getBaseSwalOptions(), {
                        title: 'Overwrite Portfolio',
                        text: 'Are you sure you want to overwrite the existing portfolio?',
                        confirmButtonClass: 'btn btn-primary',
                        confirmButtonText: 'Overwrite',
                        imageUrl: '/assets/icons-svg/icon-warning.svg'
                    });

                    swal(swalOptions).then(result => {
                        if (result && result.value) {
                            this.saveDisabled = true;
                            this.save();
                        }
                    });
                }
            });
    }

    private save() {
        let subscriptionUpload: Subscription;
        let userInfo = StorageService.get().userInfo;
        let currentDate = new Date(Date.now());
        let params = {
            accountId: userInfo.accountId,
            userId: userInfo.userId,
            portfolioName: this.portfolioNameSearch,
            sharingStatus: this.sharingStatus ? 2 : 1,
            insertDate: currentDate.toISOString()
        };

        this.lrtmService
            .runTask(this.rootComponent, 'Portfolio Upload', LongRunningTaskTypeEnum.PortfolioSecuritiesUpload, params, false, this.files)
            .subscribe(idNewPortfolio => {
                this.idNewPortfolio = idNewPortfolio;
                subscriptionUpload = this.lrtmService.tasksStatusUpdated
                    .subscribe(task => {
                        if (task.id == idNewPortfolio) {
                            if (task.taskInstanceStatus == LongRunningTaskInstanceStatusEnum.Finished) {
                                this.finishUpload();
                                subscriptionUpload.unsubscribe();
                            }
                            else if (task.taskInstanceStatus == LongRunningTaskInstanceStatusEnum.Failed) {
                                this.rootComponent.showError("The Portfolio Upload failed.");
                                subscriptionUpload.unsubscribe();
                            }
                            this.saveDisabled = false;
                        }
                    });
            });
    }

    public addCompanyToPortfolio(companyIdToAdd: string) {
        this.portfolioService.addSecurityToNewPortfolio(companyIdToAdd, this.portfolioNameSearch).subscribe(
            response => {
                if (response == null) {
                    this.rootComponent.showSuccess("Company succesfully sdded", "Success");
                    this.getValidSecurities(this.currentSkipValid, this.currentTakeValid);
                }
                else if (response.indexOf("5107") != -1) {
                    this.rootComponent.showWarning("Company security already present in matched grid");
                }
                else {
                    this.rootComponent.showError("An error occured.");
                }
            }
        );
    }

    private finishUpload() {
        let parameters = {
            taskInstanceId: this.idNewPortfolio,
            overallStatus: false,
            getStatus: false,
            getResult: true,
            deleteOnGetResult: false
        };
        this.lrtmService.finishTask(parameters).subscribe(_ => {
            this.getInvalidSecurities(this.currentSkipInvalid, this.currentTakeInvalid);
            this.getValidSecurities(this.currentSkipValid, this.currentTakeValid);
            this.lrtmService.deleteTask(this.idNewPortfolio).subscribe(_ => { });
            // this.ngxSmartModalService.getModal('portfolioCreationModal').addCustomClass('modal-xl');
            this.showFirstStep = false;
            this.showSecondStep = true;
        });
    }

    public tableOptionsChangedValidSecurities(tableOptions: TableOptions): void {
        this.currentSkipValid = tableOptions.pageOptions.skip;
        this.currentTakeValid = tableOptions.pageOptions.take;
        this.getValidSecurities(tableOptions.pageOptions.skip, tableOptions.pageOptions.take);
    }

    public tableOptionsChangedInvalidSecurities(tableOptions: TableOptions): void {
        this.currentSkipInvalid = tableOptions.pageOptions.skip;
        this.currentTakeInvalid = tableOptions.pageOptions.take;
        this.getInvalidSecurities(tableOptions.pageOptions.skip, tableOptions.pageOptions.take);
    }

    public onButtonClicked(actionOptions: any): void {
        switch (actionOptions.action) {
            case PortfolioAction.Delete:
                this.deleteSecurity(actionOptions.securityId);
                break;
            case PortfolioAction.AddToPortfolio:
                this.addSecurityToPortfolio(actionOptions.securityId);
                break;
            case PortfolioAction.UpdatePortfolioWeight:
                this.updateSecurityWeight(actionOptions.portfolioMatchId, actionOptions.value, actionOptions.isUnmatched);
                break;
        }
    }

    private deleteSecurity(securityId: string) {
        let portfolioMatchIds = [];
        portfolioMatchIds[0] = securityId;
        portfolioMatchIds[0] = portfolioMatchIds[0];
        this.portfolioService.deleteSelectedMatches(portfolioMatchIds, this.portfolioNameSearch).subscribe();
        this.getValidSecurities(this.currentSkipValid, this.currentTakeValid);
    }

    private updateSecurityWeight(portfolioMatchId: string, value: number, isUnmatched: boolean) {
        this.portfolioService.updatePortfolioWeightPortfolioCreation(portfolioMatchId, value, isUnmatched).subscribe(
            response => {
                if (response != null) {
                    this.rootComponent.showError("Error modifying weight");
                }
                else {
                    this.rootComponent.showSuccess("Weight Modified Succesfully!");
                }
            }
        )

    }

    private addSecurityToPortfolio(securityId: string) {
        this.portfolioService.addSelectedMatch(securityId, this.portfolioNameSearch).subscribe(
            response => {
                if (response != null) {
                    this.rootComponent.showError("Error company already added");
                }
                else {
                    setTimeout(() => {
                        this.rootComponent.showSuccess("Company Added Succesfully!");
                        this.getInvalidSecurities(this.currentSkipInvalid, this.currentTakeInvalid);
                        this.getValidSecurities(this.currentSkipValid, this.currentTakeValid);
                    }, 1500);
                }
            }
        );

    }

    private getInvalidSecurities(skip: number, take: number) {
        this.portfolioService.getSecurities(this.portfolioNameSearch, "invalid", skip, take, "DisplayInfo.SecurityIdentifier", true, 1).subscribe(
            data => {
                let invalidSecurities = data.portfolioMatches.map(invalidSecurity => {
                    return {
                        securityName: invalidSecurity.displayInfo.customSecurityIdentifierName,
                        securityId: invalidSecurity.displayInfo.securityIdentifier,
                        securityWeight: { value: invalidSecurity.securityWeight, action: PortfolioAction.UpdatePortfolioWeight, portfolioMatchId: invalidSecurity.id, isUnmatched: true, isEdit: false }, /* invalidSecurity.securityWeight != null ? invalidSecurity.securityWeight : "", */
                        potentialMatches: this.getPotentialMatchesNames(invalidSecurity),//invalidSecurity.matchedInfo.length >= 1 ? (invalidSecurity.matchedInfo[0].companyName != "" ? invalidSecurity.matchedInfo[0].companyName : "No potential matches found") : "No potential matches found",
                        matchedId: this.getMatchedId(invalidSecurity),//invalidSecurity.matchedInfo.length >= 1 ? invalidSecurity.matchedInfo[0].capitalIQId : "",
                        actions: this.getActionButtonForInvalidSecurities(invalidSecurity)
                    };
                });
                this.securityNotMatchedSource = invalidSecurities;
                this.securityNotMatchedCount = data.portfolioCompanyCount;

                // in order to get the number of unmatched Security IDs we need to fetch all the invalid matches and group by .displayInfo.securityIdentifier
                this.portfolioService.getSecurities(this.portfolioNameSearch, "invalid", 0, data.portfolioCompanyCount, "DisplayInfo.SecurityIdentifier", true, 1).subscribe(
                    d => {
                        this.nrOfCompaniesNotMatched = Array.from(new Set(d.portfolioMatches.map(inval => inval.displayInfo.securityIdentifier))).length;
                    }
                )

                if (this.securityNotMatchedCount > 0) this.setSecurityNotMatchedColumns();
            }
        );

    }

    private getPotentialMatchesNames(invalidSecurity: any): string[] {
        let matchedNames: string[] = [];
        invalidSecurity.matchedInfo.forEach(potentialMatch => {
            if (this.canAddCompanyToMatch(potentialMatch.matchType)) {
                matchedNames.push(potentialMatch.companyName);
            }
        });
        if (matchedNames.length == 0) matchedNames.push("No potential matches found");
        return matchedNames;
    }

    private getMatchedId(invalidSecurity: any): string[] {
        let matchedIds: string[] = [];
        invalidSecurity.matchedInfo.forEach(potentialMatch => {
            if (this.canAddCompanyToMatch(potentialMatch.matchType)) {
                matchedIds.push(potentialMatch.capitalIQId);
            }
        });
        return matchedIds;
    }

    private getActionButtonForInvalidSecurities(invalidSecurity: any): TableButton[] {
        let buttons: TableButton[] = [];
        invalidSecurity.matchedInfo.forEach(potentialMatch => {
            if (this.canAddCompanyToMatch(potentialMatch.matchType)) {
                buttons.push(
                    new TableButton("Add to Matched", {
                        action: PortfolioAction.AddToPortfolio,
                        securityId: potentialMatch.portfolioMatchId
                    }
                    ));
            }
        });
        return buttons;
    }

    private canAddCompanyToMatch(matchType: number): boolean {
        return !(matchType == 0 || matchType == 4 || matchType == 5 || matchType == 7);
    }

    private getValidSecurities(skip: number, take: number) {
        this.portfolioService.getSecurities(this.portfolioNameSearch, "valid", skip, take, "CompanyNameLowercase", true, 1).subscribe(
            data => {
                let validSecurities = data.portfolioMatches.map(validSecurity => {
                    return {
                        securityName: validSecurity.displayInfo.customSecurityIdentifierName,
                        securityId: validSecurity.displayInfo.securityIdentifier,
                        securityWeight: { value: validSecurity.securityWeight, action: PortfolioAction.UpdatePortfolioWeight, portfolioMatchId: validSecurity.id, isUnmatched: false, isEdit: false },
                        potentialMatches: new TableRouterLink(validSecurity.matchedInfo.companyName, true, validSecurity.companyNameUrlFriendly, "overview"),
                        matchedId: validSecurity.matchedInfo.capitalIQId,
                        actions: [
                            new TableButton("Remove", {
                                action: PortfolioAction.Delete,
                                securityId: validSecurity.id
                            })
                        ]
                    };
                });;
                this.securityMatchedSource = validSecurities;
                this.securityMatchedCount = data.portfolioCompanyCount;
                if (this.securityMatchedCount > 0) {
                    this.setSecurityMatchedColumns();
                }
                else {
                    this.securityMatchedColumns = [];
                }
            }
        );
    }

    public onCloseClicked() {
        this.saveDisabled = false; 
        if (this.lrtmService.tasks.length > 0) {
            this.lrtmService.tasks.forEach(task => {
                if (task.id == this.idNewPortfolio) {
                    this.lrtmService.deleteTask(task.id).subscribe(_=>{
                    });
                }
            });
        }
        this.resetForm();
    }

}